﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Globalization;
using System.Runtime.InteropServices;
using WUApiLib;

namespace Applib.WindowsUpdate
{
    /// <summary>
    /// Must add executable to firewall exception list.
    /// </summary>
    /// <see cref="http://techforum4u.com/entry.php/11-Install-Windows-Update-Using-C"/>
    /// <seealso cref="http://msdn.microsoft.com/en-us/library/windows/desktop/aa386526(v=vs.85).aspx"/>
   public class WindowsUpdate
    {
        UpdateServiceManager manager = null;
        UpdateSession session = null;

        private void Init()
        {
            Type stype = Type.GetTypeFromProgID("Microsoft.Update.Session");
            Type mgrType = Type.GetTypeFromProgID("Microsoft.Update.ServiceManager");

            manager = (UpdateServiceManager)Activator.CreateInstance(mgrType);
            session = (UpdateSession)Activator.CreateInstance(stype);
            manager.AddService2("7971f918-a847-4430-9279-4a52d1efe18d", 7, "");


            WebProxy p = new WebProxy();
            p.AutoDetect = true;
            session.WebProxy = p;
        }

        private IUpdateSearcher CreateSearcher(int idx)
        {
            if (session == null)
                throw new ArgumentException("init first. ", "session");

            IUpdateSearcher search = session.CreateUpdateSearcher();
            search.ClientApplicationID = "my app";
            search.ServiceID = manager.Services[idx].ServiceID;
            search.ServerSelection = ServerSelection.ssOthers;

            return search;
        }
        
        private void Install(IUpdateSearcher search)
        {
            string criteria = "IsInstalled=0 and Type='Software' and IsHidden=0 and BrowseOnly=0";

            ISearchResult searchResult = search.Search(criteria);

            Console.WriteLine("{2}\r\nExit code:{0}   Updates:{1}", searchResult.ResultCode, searchResult.Updates.Count, criteria);
            if (searchResult.ResultCode != OperationResultCode.orcSucceeded ||
                        searchResult.Updates.Count == 0)
                return;

            foreach (IUpdate update in searchResult.Updates)
            {
                Console.WriteLine(update.Title);
            }

            UpdateDownloader downloader = session.CreateUpdateDownloader();
            downloader.Updates = searchResult.Updates;
            downloader.Download();

            UpdateCollection updatesToInstall = new UpdateCollection();
            foreach (IUpdate update in searchResult.Updates)
            {
                if (!update.EulaAccepted)
                    update.AcceptEula();

                if (update.IsDownloaded)
                    updatesToInstall.Add(update);
            }

            IUpdateInstaller installer = session.CreateUpdateInstaller();
            installer.Updates = updatesToInstall;

            IInstallationResult installationRes = installer.Install();
            for (int i = 0; i < updatesToInstall.Count; i++)
            {
                if (installationRes.GetUpdateResult(i).HResult == 0)
                {
                    Console.WriteLine("Installed : " + updatesToInstall[i].Title);
                }
                else
                {
                    Console.WriteLine("Failed : " + updatesToInstall[i].Title);
                }
            }
        }


        public void CheckAndInstall()
        {
            Init();

            for (int i = 0; i < manager.Services.Count; i++)
            {
                try
                {
                    Install(CreateSearcher(i));
                }
                catch (Exception exc)
                {
                    Console.WriteLine(exc.Message);
                }
            }
        }

        static void Main()
        {
            WindowsUpdate wu = new WindowsUpdate();
            wu.CheckAndInstall();
        }
    }

}
